package pers.yurwisher.dota2.pudge.security;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import pers.yurwisher.dota2.pudge.constants.CacheConstant;
import pers.yurwisher.dota2.pudge.enums.UserClientType;
import pers.yurwisher.dota2.pudge.properties.SecurityProperties;
import pers.yurwisher.dota2.pudge.security.cache.OnlineUser;
import pers.yurwisher.dota2.pudge.system.service.CustomRedisCacheService;
import pers.yurwisher.dota2.pudge.system.service.ISystemUserService;

import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 2020年9月21日 10:50:20
 *
 * @author yq
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class TokenProvider implements InitializingBean {

    private final SecurityProperties properties;
    private final CustomRedisCacheService customRedisCacheService;
    private final ISystemUserService systemUserService;
    private Map<UserClientType, List<SecurityProperties.ClientTokenConfig>> userTokenConfigMap;

    @Override
    public void afterPropertiesSet() {
        //客户端token配置
        userTokenConfigMap = properties.getClientTokenConfigs().stream().collect(Collectors.groupingBy(SecurityProperties.ClientTokenConfig::getType));
    }

    /**
     * 创建Token 设置永不过期，
     * Token 的时间有效性转到Redis 维护
     *
     * @return token
     */
    public String createToken() {
        return IdUtil.simpleUUID();
    }

    /**
     * 依据Token 获取鉴权信息
     *
     * @param username 用户名
     * @param token    请求凭证
     * @return 鉴权信息
     */
    Authentication getAuthentication(String username, String token) {
        CurrentUser currentUser = systemUserService.findUserByUsername(username);
        JwtUser principal = new JwtUser(currentUser);
        return new UsernamePasswordAuthenticationToken(principal, token, principal.getAuthorities());
    }

    /**
     * 检查续期
     *
     * @param token      用户在线凭证
     * @param onlineUser 用户在线过期时间 单位秒
     */
    public void checkRenewal(String token, OnlineUser onlineUser) {
        long currentSecond = Instant.now().getEpochSecond();
        // token过期的时间(秒) - 当前时间(秒) 若在续期检查范围则续期
        long timeInt = onlineUser.getExpiredAt() - currentSecond;
        SecurityProperties.ClientTokenConfig clientTokenConfig = userTokenConfigMap.get(onlineUser.getType()).get(0);
        // 如果在续期检查的范围内，则续期
        if (timeInt <= clientTokenConfig.getDetectTimeSeconds()) {
            log.info("[{}] 续期", token);
            long renew = timeInt + clientTokenConfig.getRenewTimeSeconds();
            onlineUser.setExpiredAt(renew + currentSecond);
            customRedisCacheService.set(CacheConstant.Strings.ONLINE_USER, token, () -> onlineUser, renew,null);
        }
    }

    /**
     * 从请求中获取token
     *
     * @param request 请求
     * @return token
     */
    public String getToken(HttpServletRequest request) {
        final String requestHeader = request.getHeader(properties.getHeader());
        if (StrUtil.isNotBlank(requestHeader) && requestHeader.startsWith(properties.getPrefix())) {
            return requestHeader.replace(properties.getPrefix(), "");
        } else {
            log.debug("非法Token：{}", requestHeader);
        }
        return null;
    }

}
